home *** CD-ROM | disk | FTP | other *** search
- ;;; -*- Base: 10; Mode: Scheme; Syntax: MIT Scheme; Package: USER -*-
- ;;
- ;; SEQUENCE.SCM
- ;;
- ;; July 7, 1991
- ;; Minghsun Liu
- ;;
- ;; Some definitions related to CommonLisp datatyp SEQUENCE.
- ;;
- ;;
- ;; The following(s) is(are) defined:
- ;;
- ;; (NSUBSTITUTE-IF NEWITEM PRED SEQUENCE . KEYWORDS)
- ;; (NSUBSTITUTE-IF-NOT NEWITEM PRED SEQUENCE . KEYWORDS)
- ;; :TEST
- ;; :TEST-NOT
- ;; :KEY
- ;; :FROM-END
- ;; :START
- ;; :END
- ;; :START1
- ;; :START2
- ;; :END1
- ;; :END2
- ;; (FIND ITEM SEQ . KEYWORDS)
- ;; (SEARCH SEQ1 SEQ2 . KEYWORDS)
- ;; (CL-SORT SEQ PRED . KEYWORD)
- ;; (POSITION ITEM SEQ . KEYWORDS)
- ;; (ELT SEQ INDEX)
- ;; (COUNT ITEM SEQ . KEYWORDS)
- ;; (CONCATENATE RESULT-TYPE . SEQUENCES)
- ;; (COUNT-IF TEST SEQ . KEYWORDS)
- ;; (FILL SEQ ITEM . KEYWORDS)
- ;;
- (declare (usual-integrations))
-
- ;;
- ;; (NSUBSTITUTE-IF NEWITEM PRED SEQUENCE . KEYWORDS)
- ;;
- ;; change a sequence by substituting NEWITEM for old ones that satisfy
- ;; the PRED test. A sequence is either of type list, vector, string.
- ;;
- ;; P.S. For now, none of the keyword is implemented.
- ;;
- (define (nsubstitute-if newitem pred sequen #!rest keywords)
- (if (not (null? keywords))
- ;; just to be sure....
- (error "NSUBSTITUTE-IF: Keywords not supported for now.")
- (let ((temp '()))
- (define (nsubstitute-if-aux cur-sequence)
- (cond ((null? cur-sequence)
- (if (array? sequen)
- temp
- sequen))
- ((pred (car cur-sequence))
- (set-car! cur-sequence newitem)
- (nsubstitute-if-aux (cdr cur-sequence)))
- (else (nsubstitute-if-aux
- (cdr cur-sequence)))))
- (cond ((array? sequen)
- (set! temp (sequen 'just-the-array-maam))
- (if (and (not (vector? temp)) (null? (sequen 'array-dimensions)))
- (if (pred temp)
- (sequen 'change-myself newitem))
- (begin
- (set! temp (vector->list temp))
- (sequen 'change-myself (list->vector (nsubstitute-if-aux temp))))))
- ((list? sequen)
- (nsubstitute-if-aux sequen))
- ((vector? sequen)
- ;; this is hackish and inconsistent but is due to the
- ;; way vectors are implemented in MIT Scheme.
- (set! sequen (vector->list sequen))
- (list->vector (nsubstitute-if-aux sequen)))
- ((string? sequen)
- (set! sequen (string->list sequen))
- (string->list (nsubstitue-if-aux sequen)))
- (else (error "NSUBSTITUTE-IF: Not a sequence")
- (write-line cur-sequence))))))
-
- ;;
- ;; (NSUBSTITUTE-IF-NOT NEWITEM PRED SEQUEN . KEYWORDS)
- ;;
- ;; change a sequence by substituting NEWITEM for old ones that do not
- ;; satisfy the PRED test.
- ;;
- ;; P.S. This is written in terms of NSUBSTITUE-IF.
- ;;
- (define (nsubstitute-if-not newitem pred sequen #!rest keywords)
- (if (not (null? keywords))
- (error "NSUBSTITUTE-IF-NOT: Keywords not supported for now." keywords)
- (nsubstitute-if
- newitem
- (lambda (obj) (not (pred obj)))
- sequen)))
-
- ;;
- ;; :TEST
- ;; :TEST-NOT
- ;; :KEY
- ;; :FROM-END
- ;; :START
- ;; :END
- ;; :START1
- ;; :START2
- ;; :END1
- ;; :END2
- ;;
- ;; are all keywords used by FIND, etc. and should be constant.
- ;;
- (define :test ':test)
- (define :test-not ':test-not)
- (define :key ':key)
- (define :from-end ':from-end)
- (define :start ':start)
- (define :end ':end)
- (define :start1 ':start1)
- (define :start2 ':start2)
- (define :end1 ':end1)
- (define :end2 ':end2)
-
- ;;
- ;; (FIND ITEM SEQ . KEYWORDS)
- ;;
- ;; returns an element within a sequence that satisfies a test.
- ;;
- ;; P.S. For now the keyfnc defaults to the identity and perhaps it
- ;; should be optimized somehow.
- ;;
- (define (find item seq #!rest keywords)
- (let ((test-pos? #t)
- (pred eqv?)
- (temp '())
- (keyfnc (lambda (obj) obj))
- (fe #f)
- (sn 0)
- (en '()))
- (define (process-keywords unprocessed-kw)
- (if (null? unprocessed-kw)
- 'done!
- (case (car unprocessed-kw)
- (:test-not (set! test-pos? #f)
- (set! pred (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:test (set! pred (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:key (if (cadr unprocessed-kw)
- (set! keyfnc (cadr unprocessed-kw)))
- (process-keywords (cddr unprocessed-kw)))
- (:from-end (set! fe (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:start (set! sn (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:end (set! en (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (else (write-line unprocessed-kw)
- (error "FIND: Invalid keyword")))))
- (define (find-aux sequ)
- (cond ((null? sequ) '())
- ((eq? test-pos?
- (pred (keyfnc (car sequ)) item)) (car sequ))
- (else (find-aux (cdr sequ)))))
- (define (get-subsequence)
- (if en
- (sublist seq sn en)
- (sublist seq sn (length seq))))
- ;; The approach taken here is to convert everything into list
- ;; since its probably the most general structure that can
- ;; accomodate all possible data.
- (process-keywords keywords)
- (when fe (set! seq (reverse seq)))
- (set! temp (seq 'just-the-array-maam))
- (cond ((array? seq) (if (and (not (vector? temp))
- (null? (seq 'array-dimensions)))
- (set! seq (list temp))
- (set! seq (vector->list temp)))
- (find-aux (get-subsequence)))
- ((vector? seq) (set! seq (vector->list seq))
- (find-aux (get-subsequence)))
- ((string? seq) (set! seq (string->list seq))
- (set! item (name->char item))
- (let ((result
- (find-aux (get-subsequence))))
- (if result
- (char->name result)
- '())))
- ((list? seq) (find-aux (get-subsequence)))
- (else (error "FIND: Not a sequence" seq)))))
-
- ;;
- ;; (SEARCH SEQ1 SEQ2 . KEYWORDS)
- ;;
- ;; search one sequence for another on contained in it.
- ;;
- (define (search seq1 seq2 #!rest keywords)
- (let ((test-pos? #t)
- (pred eqv?)
- (keyfnc (lambda (obj) obj))
- (fe #f)
- (temp1 '())
- (temp2 '())
- (sn1 0)
- (en1 '())
- (sn2 0)
- (en2 '())
- (ind -1)
- (temp-end 0))
- (define (process-keywords unprocessed-kw)
- (if (null? unprocessed-kw)
- 'done
- (case (car unprocessed-kw)
- (:test-not (set! test-pos? #f)
- (set! pred (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:test (set! pred (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:key (if (cadr unprocessed-kw)
- (set! keyfnc (cadr unprocessed-kw)))
- (process-keywords (cddr unprocessed-kw)))
- (:from-end (set! fe (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:start1 (set! sn1 (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:end1 (set! en1 (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:start2 (set! sn2 (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:end2 (set! en2 (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (else (write-line unprocessed-kw)
- (error "SEARCH: Invalid keyword")))))
- (define (search-aux-1 sequ1-sequ2)
- (let ((sequ1 (car sequ1-sequ2))
- (sequ2 (cadr sequ1-sequ2)))
- (set! temp-end (length sequ2))
- (set! ind (+ ind sn2))
- (search-aux-2 sequ1 sequ2)))
- (define (search-aux-2 s1 s2)
- (cond ((not (null? s2))
- (set! ind (1+ ind))
- (search-aux-3 s1 (sublist s2 ind temp-end)))
- (else #f)))
- (define (search-aux-3 l1 l2) ;; can't think of a better name;
- ;; sequel syndrome.
- (cond ((null? l1)
- ind)
- ((null? l2)
- '())
- ((eq? test-pos?
- (pred (keyfnc (car l1))
- (keyfnc (car l2))))
- (search-aux-3 (cdr l1) (cdr l2)))
- (else
- (search-aux-2 seq1 seq2))))
- (define (proc-result result)
- (if (and fe result)
- (set! result (- (length seq2) (+ result (length seq1)))))
- (if (and (not (zero? sn2)) result)
- (set! result (+ result sn2)))
- result)
- (define (get-subsequence)
- (if fe
- (begin
- (set! seq2 (reverse seq2))
- (set! seq1 (reverse seq1))))
- (list (sublist seq1 sn1 (if en1 en1 (length seq1)))
- (sublist seq2 sn2 (if en2 en2 (length seq2)))))
- ;; The method implemented here follows the same line of thinking
- ;; as that described in FIND.
- (process-keywords keywords)
- (cond ((and (array? seq1) (array? seq2))
- (set! temp1 (seq1 'just-the-array-maam))
- (set! temp2 (seq2 'just-the-array-maam))
- (if (null? (seq1 'array-dimensions))
- (set! temp1 (vector temp1)))
- (if (null? (seq2 'array-dimensions))
- (set! temp2 (vecotr temp2)))
- (set! seq1 (vector->list temp1))
- (set! seq2 (vector->list temp2))
- (proc-result (search-aux-1 (get-subsequence))))
- ((and (vector? seq1) (vector? seq2))
- (set! seq1 (vector->list seq1))
- (set! seq2 (vector->list seq2))
- (proc-result (search-aux-1 (get-subsequence))))
- ((and (string? seq1) (string? seq2))
- (set! seq1 (string->list seq1))
- (set! seq2 (string->list seq2))
- (set! item (name->char item))
- (proc-result (search-aux-1 (get-subsequence))))
- ((and (list? seq1) (list? seq2))
- (proc-result (search-aux-1 (get-subsequence))))
- (else (error "SEARCH: Not sequences" seq1 seq2)))))
-
- ;;
- ;; (CL-SORT SEQ PRED . KEYWORD)
- ;;
- ;; sort a sequence according to some criterion. (One note though, this
- ;; is not guranteed to be destructive.)
- ;;
- (define (cl-sort seq pred #!rest keyword)
- (let ((keyfnc '()))
- (define (process-keyword)
- (if (not (null? keyword))
- (if (eq? (car keyword) :key)
- (set! keyfnc (cadr keyword))
- (error "CL-SORT: unknown keyword" keyword))))
- (define (get-predicate)
- (if keyfnc
- (lambda (x y)
- (let ((a (keyfnc x))
- (b (keyfnc y)))
- (or (pred a b)
- (equal? a b))))
- (lambda (x y)
- (or (pred a b) (equal? a b)))))
- (process-keyword)
- (cond ((array? seq)
- (if (null? (seq 'array-dimensions))
- (seq 'just-the-array-maam)
- (seq 'change-myself (sort (just-the-array-maam seq) (get-predicate)))))
- ((string? seq)
- (set! seq (string->list seq))
- (list->string (sort seq (get-predicate))))
- ((vector? seq)
- (sort seq (get-predicate)))
- ((list? seq)
- (sort seq (get-predicate)))
- (else (error "CL-SORT: Not a sequence" seq)))))
-
-
- ;;
- ;; (POSITION ITEM SEQ . KEYWORDS)
- ;;
- ;; locates an element in a sequence and returns the position of ITEM.
- ;;
- (define (position item seq #!rest keywords)
- (let ((test-pos? #t)
- (pred eqv?)
- (keyfnc (lambda (obj) obj))
- (fe #f)
- (sn 0)
- (post-ind 0)
- (en '()))
- (define (process-keywords unprocessed-kw)
- (if (null? unprocessed-kw)
- 'done!
- (case (car unprocessed-kw)
- (:test-not (set! test-pos? #f)
- (set! pred (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:test (set! pred (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:key (if (cadr unprocessed-kw)
- (set! keyfnc (cadr unprocessed-kw)))
- (process-keywords (cddr unprocessed-kw)))
- (:from-end (set! fe (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:start (set! sn (cadr unprocessed-kw))
- (set! post-ind sn)
- (process-keywords (cddr unprocessed-kw)))
- (:end (set! en (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (else (write-line unprocessed-kw)
- (error "POSITION: Invalid keyword")))))
- (define (get-subsequence)
- (if en
- (sublist seq sn en)
- (sublist seq sn (length seq))))
- (define (post-aux sequ)
- (cond ((null? sequ) '())
- ((eq? test-pos? (pred (keyfnc (car sequ)) item))
- post-ind)
- (else
- (set! post-ind (1+ post-ind))
- (post-aux (cdr sequ)))))
- (define (proc-res result)
- (if (and result fe)
- (set! result (- (length seq) (1+ result))))
- result)
- (process-keywords keywords)
- (when fe (set! seq (reverse seq)))
- (cond ((array? seq) (if (null? (seq 'array-dimensions))
- (set! seq (list (seq 'just-the-array-maam)))
- (set! seq (vector->list (just-the-array-maam
- seq))))
- (proc-res (post-aux (get-subsequence))))
- ((vector? seq) (set! seq (vector->list seq))
- (proc-res (post-aux (get-subsequence))))
- ((string? seq) (set! seq (string->list seq))
- (set! item (name->char item))
- (proc-res (post-aux (get-subsequence))))
- ((list? seq) (proc-res (post-aux (get-subsequence))))
- (else (error "POSITION: Not a sequence" seq)))))
-
-
- ;;
- ;; (ELT SEQ INDEX)
- ;;
- ;; return the element of a sequence at a given index.
- ;;
- (define (elt seq index)
- (cond ((array? seq) (seq 'array-ref index))
- ((vector? seq) (vector-ref seq index))
- ((list? seq) (list-ref seq index))
- ((string? seq) (string-ref seq index))
- (else (error "ELT: Not a sequence" seq))))
-
-
- ;;
- ;; (COUNT ITEM SEQ . KEYWORDS)
- ;;
- ;; count the numer of ITEM in SEQ that satisfy a test.
- ;;
- (define (count item seq #!rest keywords)
- (let ((temp '())
- (cur-count 0)
- (test-pos? #t)
- (pred eqv?)
- (keyfnc (lambda (obj) obj))
- (fe #f)
- (sn 0)
- (en '()))
- (define (process-keywords unprocessed-kw)
- (if (null? unprocessed-kw)
- 'done!
- (case (car unprocessed-kw)
- (:test-not (set! test-pos? #f)
- (set! pred (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:test (set! pred (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:key (if (cadr unprocessed-kw)
- (set! keyfnc (cadr unprocessed-kw)))
- (process-keywords (cddr unprocessed-kw)))
- (:from-end (set! fe (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:start (set! sn (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:end (set! en (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (else (write-line unprocessed-kw)
- (error "COUNT: Invalid keyword")))))
- (define (count-aux sequ)
- (cond ((null? sequ) cur-count)
- ((eq? test-pos?
- (pred (keyfnc (car sequ)) item))
- (set! cur-count (1+ cur-count))
- (count-aux (cdr sequ)))
- (else (count-aux (cdr sequ)))))
- (define (get-subsequence)
- (if en
- (sublist seq sn en)
- (sublist seq sn (length seq))))
- ;; The approach taken here is to convert everything into list
- ;; since its probably the most general structure that can
- ;; accomodate all possible data.
- (process-keywords keywords)
- (when fe (set! seq (reverse seq)))
- (cond ((array? seq) (set! temp (seq 'array-dimensions))
- (set! seq (just-the-array-maam seq))
- (if (null? temp)
- (set! seq (list seq))
- (set! seq (vector->list seq)))
- (count-aux (get-subsequence)))
- ((vector? seq) (set! seq (vector->list seq))
- (count-aux (get-subsequence)))
- ((string? seq) (set! seq (string->list seq))
- (set! item (name->char item))
- (count-aux (get-subsequence)))
- ((list? seq) (count-aux (get-subsequence)))
- (else (error "COUNT: Not a sequence" seq)))))
-
-
- ;;
- ;; (CONCATENATE RESULT-TPYE . SEQUENCES)
- ;;
- ;; join several sequences into one.
- ;;
- (define (concatenate result-type #!rest sequences)
- (define (transform-all seq)
- (cond ((list? seq) seq)
- ((array? seq) (vector->list (seq 'just-the-array-maam)))
- ((vector? seq) (vector->list seq))
- ((string? seq) (string->list seq))
- (else "CONCATENATE: not a sequence" seq)))
- (let ((res-list
- (apply append (map transform-all sequences))))
- (case result-type
- ((string) (list->string res-list))
- ((vector) (write-line "Warning: CONCATENATE")
- (make-array (list (length res-list)) :initial-contents res-list))
- ((list) res-list)
- (else (error "CONCATENATE: unkown result-type" result-type)))))
-
-
- ;;
- ;; (COUNT-IF TEST SEQ . KEYWORDS)
- ;;
- ;; count the number of elements which satisfy a test in a sequence.
- ;;
- (defmacro (count-if test seq #!rest keywords)
- (let ((key-exist? (memq ':key keywords)))
- (if key-exist?
- `(count #t
- ,seq
- :key (lambda (elem) (,test (,(cadr key-exist?) elem)))
- ,@(delete ':key (delete (cadr key-exist?) keywords)))
- `(count #t
- ,seq
- :key (lambda (elem) (,test elem))
- ,@keywords))))
-
-
- ;;
- ;; (FILL SEQ ITEM . KEYWORDS)
- ;;
- ;; replaces items in a sequence with a given item.
- ;;
- (define (fill seq item #!rest keywords)
- (let ((temp '())
- (sn 0)
- (en '()))
- (define (process-keywords unprocessed-kw)
- (if (null? unprocessed-kw)
- 'done!
- (case (car unprocessed-kw)
- (:start (set! sn (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (:end (set! en (cadr unprocessed-kw))
- (process-keywords (cddr unprocessed-kw)))
- (else (write-line unprocessed-kw)
- (error "FILL: Invalid keyword")))))
- (define (fill-aux cur-list)
- (if (null? cur-list)
- 'done
- (begin
- (set-car! cur-list item)
- (fill-aux (cdr cur-list)))))
- (define (get-subsequence sequ)
- (if en
- (sublist sequ sn en)
- (sublist sequ sn (length sequ))))
- (process-keywords keywords)
- (cond ((array? seq)
- (set! temp (seq 'just-the-array-maam))
- (if (null? (seq 'array-dimensions))
- (set! temp (vector temp)))
- (set! temp (vector->list temp))
- (seq 'change-myself (list->vector (fill-aux (get-subsequence temp)))))
- ((vector? seq)
- (list->vecotr (fill-aux (vector->list (get-subsequence seq)))))
- ((string? seq)
- (list->string (fill-aux (string->list (get-subsequence seq)))))
- ((list? seq)
- (fill-aux (get-subsequence seq)))
- (else (error "FILL: Not a sequence" seq)))))
-
-
-
-